﻿using System;
using System.Collections.Generic;

namespace Activity.II
{
	/// <summary>
	/// Тип делегата для фиксирование ошибки сервера.
	/// </summary>
	public delegate void ErrorDelegate(object sender, string error);

	/// <summary>
	/// Персональный компьютер для хостинга игрового сервера.
	/// </summary>
	public class PC : Computer
	{
		/// <summary>
		/// Событие, возникающее при системной ошибке.
		/// </summary>
		public event ErrorDelegate SystemCrash;

		// Время последнего сбоя сервера
		protected DateTime lastCrashTime = DateTime.Now;

		/// <summary>
		/// Создать новый экземпляр сервера на базе ПК.
		/// </summary>
		/// <param name="name">Название сервера.</param>
		public PC (string name) : base(name)
		{
			// Может возникнуть любая известная ошибка
			foreach (int error in Enum.GetValues(typeof(Error)))
				errors.Add(error);

			// Случайное число максимального количества игроков в заданных пределах [5;24]
			var next = random.Next(5, 25);

			// Округляем число вниз по модулю 5 [5;20]
			var maxPlayers = next - next % 5;
			Players = new List<string>(maxPlayers);
		}

		/// <summary>
		/// Подключить игрока к серверу.
		/// </summary>
		/// <param name="playerName">Имя игрока.</param>
		/// <returns>Истина при успешном подключении, в противном случае ложь.</returns>
		public override bool Connect (string playerName)
		{
			// Перегрузка сервера
			if (Players.Count >= Players.Capacity)
			{
				const string error = "Ошибка: Сервер перегружен! Все игроки отключены!";
				// Фиксируем ошибку
				Log(error);
				lastCrashTime = DateTime.Now;
				// Отключаем игроков
				Players.Clear();
				// Вызываем событие
				if (SystemCrash != null) SystemCrash(this, error);
				return false;
			}

			// 25% вероятность ошибки при подключении
			var hasError = new Random().Next(0, 100) < 25;
			if (hasError)
			{
				// Фиксируем ошибку
				Log("Ошибка: Подключение игрока не удалось: " + playerName);
			}
			else
			{
				// Добавляем игрока в список
				Players.Add(playerName);
			}

			// Возвращаем результат
			return hasError;
		}

		/// <summary>
		/// Текстовое представление данного объекта.
		/// </summary>
		public override string ToString ()
		{
			var upTime = DateTime.Now - lastCrashTime;
			return string.Format("Тип: ПК") +
				   string.Format("\r\nИгроков: [{0}/{1}]", Players.Count, Players.Capacity) +
				   string.Format("\r\nНагрузка: {0:00}%", GetLoad() * 100) +
				   string.Format("\r\nВремя работы: {0:00}:{1:00}:{2:00}", upTime.Hours, upTime.Minutes, upTime.Seconds);
		}
	}
}
